#include "mpp_screens.h"
#include  <iostream>

drmModeModeInfoPtr mpp_screens::mpp_find_modeInfo(drmModeConnectorPtr connector,
                        uint32_t width, uint32_t height,uint32_t vrefresh)
{
    int  j = 0;
    drmModeModeInfoPtr modeInfo = NULL;
    printf("找到%d种显示模式\n",connector->count_modes);
    
    modeInfo = &connector->modes[0];
    for ( j = 0; j <connector->count_modes; j++) {
        drmModeModeInfoPtr tmp_m = &connector->modes[j];
        printf(" width :%d height:%d vrefresh:%d type:%02X ,%s\n",
                                                                                        tmp_m->hdisplay,
                                                                                        tmp_m->vdisplay,
                                                                                        tmp_m->vrefresh,
                                                                                        tmp_m->type,tmp_m->name);
        if (   //(tmp_m->type & DRM_MODE_TYPE_PREFERRED) && 
                        tmp_m->hdisplay == width && 
                        tmp_m->vdisplay == height && 
                        tmp_m->vrefresh == vrefresh){
                printf("找到最适合的显示模式 width :%d height:%d\n",tmp_m->hdisplay,tmp_m->vdisplay);          
                modeInfo = tmp_m;
                break;   
            }                       
    }
    if(j ==connector->count_modes){
        printf("未找到最适合的显示模式\n");
    }
    return modeInfo;
}
 drmModeEncoderPtr   mpp_screens::mpp_find_encoder(drmModeConnectorPtr connector)
 {
     int  j = 0;
    drmModeEncoderPtr encoder = NULL;
    vector<drmModeEncoderPtr> tmp = mpp_dev_get_encoders();
     if (!connector->encoder_id) {       //--如果这个连接器中没有包含编码器的ID则选择第一个作为默认的编码器ID
            /*
             * default drm encoder not attached connector, just
             * select the first one.
             */
            if (!tmp.empty()) {
                encoder = tmp.at(0);
                connector->encoder_id = encoder->encoder_id;
            } else {
                printf("没有编码器可用于当前连接器\n");
                return NULL;
            }
            printf("连接器%d中没有编码器的ID,当前程序默认选择第一个编码器作为本连接器的编码器\n",
                                                                                                        connector->connector_id);
            printf("当前编码器ID:%d\n",encoder->encoder_id);                                                                                            
    }

    for (j = 0; j < tmp.size(); j++) {
        if (tmp.at(j)->encoder_id == connector->encoder_id){
            encoder = tmp.at(j);
            printf("使用编码器ID:%d\n",encoder->encoder_id);    
            break;
        }
            
    }
    if (j == tmp.size()) {
        printf("没有编码器可用于当前连接器\n");
        return NULL;
    }
    return encoder;
       
 }

drmModeCrtcPtr   mpp_screens::mpp_find_crtc(drmModeEncoderPtr encoder)
{
    drmModeCrtcPtr    crtc      = NULL,tmp = NULL;
    int  j = 0;
    vector<drmModeCrtcPtr>   v_tmp = mpp_dev_get_crtcs();
    if (!encoder->crtc_id) {
        /*
            * default drm crtc not attached encoder, just
            * select the first one.
            */
        if (!v_tmp.empty()) {
            crtc = v_tmp.at(0);
            encoder->crtc_id = crtc->crtc_id;
            printf("编码器%d中没有扫描器的ID,当前程序默认选择第一个扫描器作为本编码器的扫描器\n",
                                                                                                        encoder->encoder_id);
        } else {
            printf("no crtc attached to the encoder\n");
            return NULL;
        }
    }

    for (j = 0; j < v_tmp.size(); j++) {
        tmp = v_tmp.at(j);
        if (tmp->crtc_id == encoder->crtc_id){  
            crtc = tmp;
            printf("使用扫描器ID:%d\n",tmp->crtc_id);      
            break;
        }
    }
    if (j == v_tmp.size()) {
        printf("could not find crtc for the encoder\n");
        return NULL;
    }

    return crtc;
}

mpp_screens::mpp_screens(uint32_t width, uint32_t height,
                                uint32_t vrefresh,
                                uint32_t format):
                                width(width),
                                height(height),
                                vrefresh(vrefresh),
                                format(format),
                                mpp_display_planes(),
                                m_current_screens(NULL)
{   
    //br_file = fopen(background.c_str(),"r");
}

bool mpp_screens::mpp_start_display()
{
    int j = 0,ret = 0;
   vector<drmModeConnectorPtr> v_cnn  ;
    if(mpp_display_init_element())
        return false;
    v_cnn = mpp_dev_get_connectors();

    printf("初始化各个子设备 其中有%d个连接器\n",v_cnn.size());
    //--进行vector的遍历
    for (std::vector<drmModeConnectorPtr>::iterator it = v_cnn.begin() ; it != v_cnn.end(); ++it){
        
        drmModeConnectorPtr tmp_connector =  (*it);
        drmModeModeInfoPtr tmp_modeInfo  = NULL;
        drmModeEncoderPtr tmp_encoder  = NULL;
        drmModeCrtcPtr        tmp_crtc      = NULL;
        drmModePlanePtr      tmp_plane   =  NULL;
        if ( tmp_connector->connection != DRM_MODE_CONNECTED ){   //--进行连接器的确认
            printf("没有连接设备\n");
            continue;
        }
           

        if (!tmp_connector->count_modes) {
            printf("connector has no modes, skipping\n");
            continue;
        }

//********************************找到分辨率**********************************
        printf("用户输入的分辨率 width %d,height%d,verfresh %d \n",this->width,this->height,this->vrefresh);
        tmp_modeInfo = mpp_find_modeInfo(tmp_connector,this->width,this->height,this->vrefresh);
        if(!tmp_modeInfo){

            continue;
        }

//*********************************找到编码器**********************************
        tmp_encoder =    mpp_find_encoder(tmp_connector);
        if(!tmp_encoder){
            continue;
        }
//****************************************************************************

//*********************************找到扫描器***********************************
        tmp_crtc = mpp_find_crtc(tmp_encoder);
        if(!tmp_crtc){
            continue;
        }
//****************************************************************************        


 //**       
        tmp_plane =   mpp_get_planes(this->format);   
        if(!tmp_plane){
            continue;
        }
        cout<<"plane ID:"<<tmp_plane->plane_id<<" plane's crc ID:"<<tmp_plane->crtc_id <<" crc ID:"<<tmp_crtc->crtc_id << endl;

        printf("DRM 设备文件描述符:  %d \n",mpp_display_dev_get_fd());
        mpp_display_buffer *buffer_tmp = new mpp_display_buffer(mpp_display_dev_get_fd(),this->width,this->height,this->format,0);
        if(buffer_tmp && buffer_tmp->mpp_is_exist()){
                buffer_tmp->mpp_fill_bo( 0x00, 0xFF, 0x00, 0x00);
        }else{
             return false;
        } 
        
        ret = mpp_display_dev_setCrtc(tmp_crtc->crtc_id,
                                buffer_tmp->mpp_buffer_get_id(),
                                0,0,
                                &tmp_connector->connector_id,1,tmp_modeInfo);
        if(ret){
            printf("设置显示失败 crtcID:%d,bufferID:%d \n",tmp_crtc->crtc_id,buffer_tmp->mpp_buffer_get_id());
            return false;
        }
        
        printf("开始显示\n");

        current_screens *tmp_screens = new current_screens; 

        tmp_screens->buffer = buffer_tmp;
        tmp_screens->connector = tmp_connector;
        tmp_screens->encoder = tmp_encoder;
        tmp_screens->crtc = tmp_crtc;
        tmp_screens->plane = tmp_plane;


            /*
            * Todo:
            * I don't know why crtc mode is empty, just copy PREFERRED mode
            * for it.
            */
            ///我也不知道为啥要这样复制，有可能为了内部的赋值而已
            memcpy(&tmp_screens->crtc->mode, tmp_modeInfo, sizeof(drmModeModeInfoPtr));

            m_current_screens =tmp_screens;
        
    }

    return true;
}
void *mpp_screens::mpp_get_addr()
{
    if(m_current_screens){
        return m_current_screens->buffer->mpp_buffer_get_addr();
    }
}
bool mpp_screens::mpp_is_startDisplay()
{
    if(m_current_screens)
        return true;
    return false;
}
int mpp_screens::mpp_setPlane(uint32_t fb_id, uint32_t flags,
			   int32_t crtc_x, int32_t crtc_y,
			   uint32_t crtc_w, uint32_t crtc_h,
			   uint32_t src_x, uint32_t src_y,
			   uint32_t src_w, uint32_t src_h )
{
    
    //printf("drm fd %d plane id %d crtc id %d \n",this->mpp_display_dev_get_fd(),this->m_current_screens->plane->plane_id,this->m_current_screens->crtc->crtc_id);
   return    drmModeSetPlane(this->mpp_display_dev_get_fd(), 
                        this->m_current_screens->plane->plane_id,
                        this->m_current_screens->crtc->crtc_id, 
                        fb_id,   //--将BUFFER ID赋值就可以显示
                        flags, crtc_x, crtc_y,
                        crtc_w,
                        crtc_h,
                        src_x, src_y,  
                        src_w ,  src_h );
   
}
mpp_screens::~mpp_screens()
{
    
    if(m_current_screens)
    {
        mpp_planes_put_plane(m_current_screens->plane);
        if(m_current_screens->buffer){
            delete m_current_screens->buffer;
             m_current_screens->buffer = NULL;
        }
        delete m_current_screens;
        m_current_screens = NULL;
    }
}
